/*=============================================================================
*
*   Copyright (C) 2020 All rights reserved.
*
*   Filename:		tip_interface.hpp
*
*   Author: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Date: 2020-03-23 17:17
*
*   Last Editors: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Last modified:	2020-08-04 01:26
*
*   Description:
*
=============================================================================*/
#ifndef CRACK_TIP_INTERFACE_H
#define CRACK_TIP_INTERFACE_H

#include "../geometry/basic_geometry.hpp"
#include "../util/component.hpp"
#include "sif_calculator_interface.hpp"

namespace geoxfem {
namespace xfem {

template <typename CrackType>
struct TipInterface : util::Component<CrackType> {
  using Crack          = CrackType;
  using Mesh           = typename Crack::Mesh;
  using point_type     = typename Crack::point_type;
  using PointList      = typename Crack::PointList;
  using iterator       = typename PointList::iterator;
  using const_iterator = typename PointList::const_iterator;

  TipInterface(Crack* crack) : util::Component<Crack>{crack} {
    m_list_point = crack->getPoints();
  }
  virtual ~TipInterface() = default;

  /* member access{{{*/
  virtual int getSign() const = 0;

  virtual void appendFront(point_type&) {
    return;
  }
  virtual void appendBack(point_type&) {
    return;
  }

  const point_type& getTip() const {
    return m_list_point.front();
  }
  _real getTangentDirection() const {
    return geometry::anti_clock_angle_from_x_axis(*begin(),
                                                  *std::next(begin()));
  }
  VectorXR getTangentVector() const {
    return (begin()->getCoord() - std::next(begin())->getCoord()).normalized();
  }
  VectorXR getNormalVector() const {
    VectorXR tangent = getTangentVector(), normal;
    normal.setZero(tangent.size());
    normal << -tangent[1], tangent[0];
    return normal;
  }
  /*}}}*/
  /*iterator {{{*/
  iterator begin() {
    return m_list_point.begin();
  }
  iterator end() {
    return m_list_point.end();
  }
  const_iterator begin() const {
    return m_list_point.begin();
  }
  const_iterator end() const {
    return m_list_point.end();
  }
  /*}}}*/
  /* SIF {{{*/

  /*}}}*/
protected:
  PointList m_list_point;
};

template <typename Crack>
struct HeadTip : TipInterface<Crack> { /*{{{*/
  using point_type = typename Crack::point_type;

  HeadTip(Crack* crack) : TipInterface<Crack>{crack} {}

  int getSign() const final override {
    return 1;
  }

  void appendFront(point_type& point) final override {
    this->m_list_point.emplace_front(point);
    return;
  }

  void appendBack(point_type& point) final override {
    this->m_list_point.emplace_back(point);
    return;
  }

}; /*}}}*/

template <typename Crack>
struct TailTip : TipInterface<Crack> { /*{{{*/
  using point_type = typename Crack::point_type;

  TailTip(Crack* crack) : TipInterface<Crack>{crack} {}

  int getSign() const final override {
    return -1;
  }
  void appendFront(point_type& point) final override {
    this->m_list_point.emplace_back(point);
    return;
  }

  void appendBack(point_type& point) final override {
    this->m_list_point.emplace_front(point);
    return;
  }
}; /*}}}*/

}  // namespace xfem
}  // namespace geoxfem

#endif /* CRACK_TIP_INTERFACE_H */
